/**
 * @file mem_malloc.c
 * @author your name (you@domain.com)
 * @brief 	动态内存管理，使用内存页的方式，每页内存大小为MEM_BLOCK_SIZE，最大内存为MEM_MAX_SIZE。
 * 			MEM_MAX_SIZE必须为MEM_BLOCK_SIZE的整数倍，需要分配的最大内存不能超过MEM_BLOCK_SIZE*256，即不能分配256页以上的内存,
 * 			如需超过256页则修改memmapbase 的数据类型。
 * 			占用RAM为(MEM_MAX_SIZE + MEM_MAX_SIZE / MEM_BLOCK_SIZE)字节
 * @version 0.1
 * @date 2021-06-25
 *
 * @copyright Copyright (c) 2021
 *
 */
#include "mem_malloc.h"
#include "string.h"

// 八字节对齐
#pragma pack(4)
volatile unsigned char membase[MEM_MAX_SIZE]; //内存池数组 4字节对齐
#pragma pack()
volatile unsigned char memmapbase[MEM_MAX_SIZE / MEM_BLOCK_SIZE]; //内存状态表

/**
 * @brief 释放内存
 *
 * @param ptr 内存指针
 */
void my_free ( void* ptr )
{
    int i;
    unsigned long offset;
    if ( ptr == 0 )
    {
        return ; //地址为0.
    }
    offset = ( unsigned long ) ptr - ( unsigned long ) membase;
    if ( offset < MEM_MAX_SIZE ) //偏移在内存池内.
    {
        int index = offset / MEM_BLOCK_SIZE; //偏移所在内存块号码
        int nmemb = memmapbase[index];		 //内存块数量
        for ( i = 0; i < nmemb; i++ )			 //内存块清零
        {
            memmapbase[index + i] = 0;
        }
        return ;
    }
    else
    {
        return ; //偏移超区了.
    }
}

/**
 * @brief 分配内存
 *
 * @param size 需要的内存大小
 * @return void* 分配的内存指针
 */
void* my_malloc ( unsigned long size )
{
    unsigned long offset = 0;
    unsigned long nmemb;	 //需要的内存块数
    unsigned long cmemb = 0; //连续空内存块数
    unsigned long i;
    if ( size == 0 )
    {
        return 0; //不需要分配
    }
    nmemb = size / MEM_BLOCK_SIZE; //获取需要分配的连续内存块数
    if ( size % MEM_BLOCK_SIZE )
    {
        nmemb++;
    }
    for ( offset = MEM_MAX_SIZE / MEM_BLOCK_SIZE; offset > 0; offset-- ) //搜索整个内存控制区
    {
        if ( memmapbase[offset - 1] == 0 )
        {
            cmemb++; //连续空内存块数增加
        }
        else
        {
            cmemb = 0; //连续内存块清零
        }
        if ( cmemb == nmemb ) //找到了连续nmemb个空内存块
        {
            for ( i = 0; i < nmemb; i++ ) //标注内存块非空
            {
                memmapbase[offset - 1 + i] = nmemb;
            }
            return ( void* ) ( ( unsigned long ) membase + ( ( offset - 1 ) * MEM_BLOCK_SIZE ) ); //返回偏移地址
        }
    }
    return 0; //未找到符合分配条件的内存块
}


void* my_realloc (void* mem, unsigned long size )
{
	
	void* p = my_malloc(size);
	if(mem == 0)
	{
		return p;
	}
	if(p)
	{
		unsigned long  offset = (( unsigned long )mem-( unsigned long )membase)/MEM_BLOCK_SIZE;
		unsigned long size = memmapbase[offset]*MEM_BLOCK_SIZE;
		memcpy(p,mem,size);
		my_free(mem);
		return p;
	}
	else
	{
		return 0;
	}
	

}
